package com.gvsoft.communication.common.ioadapter;

import com.gvsoft.communication.net.IoBuffer;
import com.gvsoft.communication.net.adapter.IOAdapter;
import com.gvsoft.communication.net.model.IOrder;
import com.gvsoft.communication.net.NSocket;
import sun.misc.BASE64Decoder;
import java.nio.ByteBuffer;
import java.util.regex.Pattern;


/**
 * &&&&&&&&&&&&&&&&此类已停用&&&&&&&&&&&&&&&&&&&
 * Created with IntelliJ IDEA.
 * ProjectName:gvMsgRouting
 * Author: zhaoqiubo
 * Date: 15/9/22
 * Time: 上午11:13
 * Desc: 我处理byte字节最早的方法：每个包分为两个部分：
 * 【包头】：为10进制四位数字，最大9999。不满以空格占位。
 * 【包体】定义为：
 * 所有报文和指令均有字符串组成，分为四个部分：
 * 1、指令（报文）标记，大写英文字母，每一类指令（报文）都有自己唯一的标记；
 * 2、指令（报文）流水号Rid；主动发起的指令，自动生成，最大1000000000，循环反复。被动响应的指令，为请求方的Rid回填。
 * 3、指令（报文）Token，自动生成UUID；
 * 4、指令体（报文）；
 * 除指令标记和指令流水号之外，其他两项内容，根据不同的指令（或报文），会有取舍；各部分之间以“|”作为分隔符。
 * 例如：T|128|6e7805ec-8487-4ace-9c1e-cb715888b67f
 * 5、所有报文传输，均采用UTF-8,Base64编码后传送；
 */
public class BaseAdapter implements IOAdapter {

    //断包处理，前一截包含完整包头；
    private String endPacketStr = "";
    //断包处理，前一截不包含完整包头；
    private String endBufferStr = "";
    //断包处理，前一截包含完整包头时，包体的大小标记；
    private int remainBodySize = 0;
    //定义包头的字节大小
    public final static int PACKET_HEAD_LENGTH = 8;

    @Override
    public Object analyRead(IoBuffer buf) {
        return null;
    }


    public String decode(IoBuffer b) {
        return null;
    }

    public void analyRead(NSocket nSocket, ByteBuffer byteBuffer) {

        //标记读取缓冲区起始位置
        int location = 0;
        //如果缓冲区从0到limit的数量大于包体大小标记数字
        while (byteBuffer.remaining() > PACKET_HEAD_LENGTH) {
            //包体大小标记
            String strBsize;
            //如果endPacket的字节length大于0，则证明：断包的前一截为包含包头和包体的；
            if (remainBodySize > 0) {
                location = hIncludeBody(nSocket,byteBuffer);
                continue;
                //如果endBufferStr的字节length大于0，则证明：断包的前一截仅包含包头或包头的一部分，不包含包体；
            } else if (endBufferStr.getBytes().length > 0) {
                location = hNotIncludeBody(nSocket,byteBuffer, location);
                continue;
                //进入正常处理（规范的报文处理，不考虑断包）
            } else {
                //移动缓冲区position
                strBsize = new String(byteBuffer.array(), location, PACKET_HEAD_LENGTH);
                //移动缓冲区position
                byteBuffer.position(location + PACKET_HEAD_LENGTH);
                location = byteBuffer.position();
            }
            //得到包体大小
            int byteBufferSize;
            if(!isNumeric(strBsize.trim())){
                System.out.println("remainBodySize:"+remainBodySize+",endBufferStr:"+endBufferStr+",byteBuffer String:"+byteBuffer.array().toString()+",location:"+location);
            }
            byteBufferSize = Integer.parseInt(strBsize.trim());
            //如果从缓冲区当前位置到limit大于包体大小，证明粘包了，进行包体处理。等于则为正常包体，不存在粘包现象。
            if (byteBuffer.remaining() >= byteBufferSize) {

                String strPacket = new String(byteBuffer.array(), location, byteBufferSize);
                byteBuffer.position(location + byteBufferSize);//将缓冲区的位置移动到下一个包体大小标记位置
                location = byteBuffer.position();//设定读取缓冲区起始位置
                //将字符串报文封装为类
                nSocket.asyncHandlePacket(decode(strPacket));

                //如果缓冲区当前位置到limit小于包体，证明断包了,进行断包处理
            } else {
                endPacketStr = new String(byteBuffer.array(), location, byteBuffer.limit() - location);
                remainBodySize = byteBufferSize - endPacketStr.getBytes().length;
                //已经找到断包前半截，所以把整个buffer的position调整至最后，不再处理。等待新的key进入
                byteBuffer.position(byteBuffer.limit());
            }
        }
        //处理剩余包体小于PACKET_HEAD_LENGTH的情况
        if (byteBuffer.remaining() > 0 && remainBodySize > 0) {
            location = hIncludeBody(nSocket,byteBuffer);
        }
        //处理仅包含包头前一截的报文；
        if (byteBuffer.remaining() > 0 && remainBodySize == 0) {
            //缓冲区中剩余的仅包含包头前一截的报文
            endBufferStr = new String(byteBuffer.array(), location, byteBuffer.limit() - location);
            //移动缓冲区指针到最后，代表已经保存了前一截报文，无需再进行处理；
            byteBuffer.position(byteBuffer.limit());
        }
    }

    public void analyWrite(IOrder iOrder,ByteBuffer byteBuffer) {

        byteBuffer.clear();
        String str = encode(iOrder.generateOrderStr());
        //得出整个包体的长度
        String packetSize = Integer.toString(str.getBytes().length);
        //将包体长度放入buffer的前四位
        byteBuffer.put(packetSize.getBytes());
        //因为使用了buffer池，这块儿填补空字符到未满的前四位，否则容易出现错误包头
        for (int i = packetSize.getBytes().length; i < PACKET_HEAD_LENGTH; i++) {
            byteBuffer.put(" ".getBytes());
        }
        //移动buffer的postion指针到第四位，包体将从第四位开始写入
        byteBuffer.position(PACKET_HEAD_LENGTH);
        //写入包体
        byteBuffer.put(str.getBytes());
        byteBuffer.flip();

    }

    public void onError(NSocket nSocket,Throwable t) {
        //do nothing
    }

    public String encode(String s) {
        if (s == null) {return null;}
        return (new sun.misc.BASE64Encoder()).encode(s.getBytes());
    }

    public String decode(String s) {
        if (s == null) {return null;}
        BASE64Decoder decoder = new BASE64Decoder();
        try {
            byte[] b = decoder.decodeBuffer(s);
            return new String(b);
        } catch (Exception e) {
            return null;
        }
    }

    private int hNotIncludeBody(NSocket nSocket,ByteBuffer byteBuffer, int location) {

        String strBsize;
        strBsize = (new StringBuffer(endBufferStr).append(new
                String(byteBuffer.array(), location, PACKET_HEAD_LENGTH - endBufferStr.getBytes().length))).toString();
        //移动缓冲区position
        byteBuffer.position(PACKET_HEAD_LENGTH - endBufferStr.getBytes().length);
        location = byteBuffer.position();
        //得到包体大小
        int byteBufferSize = Integer.parseInt(strBsize.trim());
        //进行报文合并，把保存的仅包含包头或包头一部分的前一截与后一截合并
        String strPacket = (new String(byteBuffer.array(), PACKET_HEAD_LENGTH - endBufferStr.getBytes().length, byteBufferSize));
        byteBuffer.position(location + byteBufferSize);//将缓冲区的位置移动到下一个包体大小标记位置
        location = byteBuffer.position();
        endBufferStr = "";
        nSocket.asyncHandlePacket(decode(strPacket));
        return location;

    }

    private int hIncludeBody(NSocket nSocket, ByteBuffer byteBuffer) {
        int location;

        String strPacket = endPacketStr + new String(byteBuffer.array(), 0, remainBodySize);
        byteBuffer.position(remainBodySize);
        location = remainBodySize;
        //处理完毕，清理断包的前一截，以便于下次使用；
        endPacketStr = "";
        //清理后一截报文的字节数标记；
        remainBodySize = 0;

        nSocket.asyncHandlePacket(decode(strPacket));
        return location;
    }
    public static boolean isNumeric(String str){
        Pattern pattern = Pattern.compile("[0-9]*");
        return pattern.matcher(str).matches();
    }
}
